// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.network.packets;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.zip.CRC32;
import zombie.core.Rand;
import zombie.core.network.ByteBufferWriter;
import zombie.core.raknet.UdpConnection;
import zombie.debug.DebugLog;
import zombie.debug.DebugOptions;
import zombie.debug.LogSeverity;
import zombie.gameStates.GameLoadingState;
import zombie.network.ConnectionManager;
import zombie.network.GameClient;
import zombie.network.GameServer;
import zombie.network.PacketValidator;
import zombie.scripting.ScriptManager;
import zombie.scripting.objects.Recipe;

public class ValidatePacket implements INetworkPacket {
    private long checksum;
    private long checksumFromClient;
    private int salt;
    private byte flags;

    public void setSalt(int _salt, boolean queued, boolean done, boolean details) {
        this.salt = _salt;
        this.flags = 0;
        this.flags = (byte)(this.flags | (queued ? 1 : 0));
        this.flags = (byte)(this.flags | (done ? 2 : 0));
        this.flags = (byte)(this.flags | (details ? 4 : 0));
    }

    public void process(UdpConnection connection) {
        if (GameClient.bClient) {
            this.checksum = this.calculateChecksum(connection, this.salt);
            GameClient.sendValidatePacket(this);
            if (DebugOptions.instance.MultiplayerFailChecksum.getValue() && (this.flags & 1) != 0) {
                ArrayList arrayList = ScriptManager.instance.getAllRecipes();
                Recipe recipe = (Recipe)arrayList.get(Rand.Next(arrayList.size()));
                recipe.TimeToMake = (float)Rand.Next(32767);
                DebugLog.Multiplayer.debugln("Failed recipe \"%s\"", recipe.getOriginalname());
            }

            if ((this.flags & 2) != 0) {
                GameLoadingState.Done();
            }
        } else if (GameServer.bServer) {
            this.salt = connection.validator.getSalt();
            this.checksum = this.calculateChecksum(connection, this.salt);
            if ((this.flags & 4) == 0) {
                if (this.checksumFromClient != this.checksum) {
                    connection.validator.failChecksum();
                }

                if (connection.validator.isFailed()) {
                    connection.validator.sendChecksum(false, false, true);
                } else {
                    connection.validator.successChecksum();
                    if ((this.flags & 1) != 0) {
                        connection.validator.sendChecksum(false, true, false);
                    }
                }
            }
        }
    }

    private long calculateChecksum(UdpConnection udpConnection, int _int) {
        if ((this.flags & 4) != 0) {
            udpConnection.validator.details.clear();
        }

        CRC32 cRC320 = new CRC32();
        CRC32 cRC321 = new CRC32();
        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
        cRC320.update(_int);

        for (Recipe recipe : ScriptManager.instance.getAllRecipes()) {
            cRC321.reset();
            byteBuffer.clear();
            cRC321.update(recipe.getOriginalname().getBytes());
            cRC321.update((int)recipe.TimeToMake);
            if (recipe.skillRequired != null) {
                for (Recipe.RequiredSkill requiredSkill : recipe.skillRequired) {
                    cRC321.update(requiredSkill.getPerk().index());
                    cRC321.update(requiredSkill.getLevel());
                }
            }

            for (Recipe.Source source : recipe.getSource()) {
                for (String string : source.getItems()) {
                    cRC321.update(string.getBytes());
                }
            }

            cRC321.update(recipe.getResult().getType().getBytes());
            cRC321.update(recipe.getResult().getModule().getBytes());
            cRC321.update(recipe.getResult().getCount());
            long _long = cRC321.getValue();
            byteBuffer.putLong(_long);
            byteBuffer.position(0);
            cRC320.update(byteBuffer);
            if ((this.flags & 4) != 0) {
                udpConnection.validator
                    .details
                    .put(
                        recipe.getOriginalname(),
                        new PacketValidator.RecipeDetails(
                            recipe.getOriginalname(),
                            _long,
                            (int)recipe.TimeToMake,
                            recipe.skillRequired,
                            recipe.getSource(),
                            recipe.getResult().getType(),
                            recipe.getResult().getModule(),
                            recipe.getResult().getCount()
                        )
                    );
            }
        }

        return cRC320.getValue();
    }

    @Override
    public void parse(ByteBuffer b, UdpConnection connection) {
        try {
            this.flags = b.get();
            if (GameClient.bClient) {
                this.salt = b.getInt();
            } else if (GameServer.bServer) {
                this.checksumFromClient = b.getLong();
                if ((this.flags & 4) != 0) {
                    connection.validator.detailsFromClient.clear();
                    int int0 = b.getInt();

                    for (int int1 = 0; int1 < int0; int1++) {
                        connection.validator.detailsFromClient.put(zombie.GameWindow.ReadString(b), new PacketValidator.RecipeDetails(b));
                    }
                }
            }
        } catch (Exception exception) {
            DebugLog.Multiplayer.printException(exception, "Parse error. Probably, \"" + connection.username + "\" client is outdated", LogSeverity.Error);
        }
    }

    @Override
    public void write(ByteBufferWriter b) {
        b.putByte(this.flags);
        if (GameServer.bServer) {
            b.putInt(this.salt);
        } else if (GameClient.bClient) {
            b.putLong(this.checksum);
            if ((this.flags & 4) != 0) {
                int _int = GameClient.connection.validator.details.size();
                b.putInt(_int);

                for (Entry entry : GameClient.connection.validator.details.entrySet()) {
                    b.putUTF((String)entry.getKey());
                    ((PacketValidator.RecipeDetails)entry.getValue()).write(b);
                }
            }
        }
    }

    @Override
    public void log(UdpConnection connection, String tag) {
        if (this.flags != 0) {
            ConnectionManager.log(tag, String.format("checksum-packet-%d", this.flags), connection);
        }
    }

    public static enum ValidateState {
        Request,
        Success;
    }
}
